﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.Geodatabase;
using System.Collections;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.ADF;
using PlanningGIS.Framework;

using PlanningGIS.ArcGIS;
using PlanningGIS.Util.Log;

namespace PlanningGIS.DataConvert.model
{
    /// <summary>
    /// 作用：根据代码导入DLG数据
    /// </summary>
    public class DlgDataImport : Operator2
    {
        private const int MAX = 200000;//计算唯一值的方式选择条件。总数小于该数，用AE的接口；大于该数，用ArrayList

        private bool validate;//是否需要验证建库方案的完整性（拿数据源作依据）
        private string sourceCodeName;//数据源入库代码依据字段名

        private ShowLoadingProcessBar showLoadingPrcessBar;//显示假进度条的委托，比如再计算唯一值时，就可以调用该委托
        private List<IFeatureClass> pFeatClsLstSource;

        //记录数据源与目标数据代码的对应关系，分点、线、面、注记来存储是因为不同几何类型有可能源数据的代码一样，所以要分开存储
        private Hashtable fcodeRelationPt;                      //点要素的代码对应关系
        private Hashtable fcodeRelationLn;                      //线要素的代码对应关系
        private Hashtable fcodeRelationPy;                      //面要素的代码对应关系
        private Hashtable fcodeRelationAnno;                    //注记要素的代码对应关系（有则按对应关系入库，无则全部入库）

        private int totalCount;
        private int rightCount;
        private int errorCount;

        private bool useGP = false;
        private List<DlgDataConvert> dlgDataConverts = null;

        #region DlgDataImportByCode members

        /// <summary>
        /// 是否用GP工具
        /// </summary>
        public bool UseGP
        {
            set { useGP = value; }
        }

        /// <summary>
        /// 是否需要验证建库方案完整性
        /// </summary>
        public bool NeedValidate
        {
            set { validate = value; }
        }

        /// <summary>
        /// 数据源依据的字段名
        /// </summary>
        public string SourceCodeName
        {
            get { return sourceCodeName; }
            set { sourceCodeName = value; }
        }

        /// <summary>
        /// 数据转换任务列表
        /// </summary>
        public List<DlgDataConvert> Task
        {
            set { dlgDataConverts = value; }
        }

        /// <summary>
        /// 显示假进度条的委托，比如再计算唯一值时，就可以调用该委托
        /// </summary>
        public ShowLoadingProcessBar ShowLoadingProcessBar
        {
            set { showLoadingPrcessBar = value; }
        }

        /// 从基础数据的XML建库方案规则中获得入库数据源
        /// </summary>
        public List<IFeatureClass> FeatClsListSource
        {
            get { return pFeatClsLstSource; }
            set { pFeatClsLstSource = value; }
        }

        /// <summary>
        /// 点要素的代码对应关系
        /// </summary>
        public Hashtable FcodeRelationPt
        {
            get { return fcodeRelationPt; }
            set { fcodeRelationPt = value; }
        }

        /// <summary>
        /// 线要素的代码对应关系
        /// </summary>
        public Hashtable FcodeRelationLn
        {
            get { return fcodeRelationLn; }
            set { fcodeRelationLn = value; }
        }

        /// <summary>
        /// 面要素的代码对应关系
        /// </summary>
        public Hashtable FcodeRelationPy
        {
            get { return fcodeRelationPy; }
            set { fcodeRelationPy = value; }
        }

        /// <summary>
        /// 注记要素的代码对应关系
        /// </summary>
        public Hashtable FcodeRelationAnno
        {
            get { return fcodeRelationAnno; }
            set { fcodeRelationAnno = value; }
        }
        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        public DlgDataImport()
        {
            showLoadingPrcessBar = Waiting;
            totalCount = 0;
            rightCount = 0;
            errorCount = 0;

            validate = false;
        }

        /// <summary>
        /// 重写停止操作事件，使得本次任务中的每一项皆停止入库
        /// </summary>
        /// <returns></returns>
        public override bool Stop()
        {

            if (dlgDataConverts != null && dlgDataConverts.Count != 0)
            {
                foreach (DlgDataConvert dlgDataConvert in dlgDataConverts)
                {
                    dlgDataConvert.Stop();
                }
            }

            return base.Stop();
        }

        /// <summary>
        /// DLG数据入库
        /// </summary>
        /// <returns></returns>
        public override bool Operate()
        {
            if (dlgDataConverts == null || dlgDataConverts.Count == 0)
            {
                LogHelper.WriteErrLog("入库任务未设置！");
                return false;
            }

            if (validate)
            {
                showLoadingPrcessBar(true);
                Validate();
                showLoadingPrcessBar(false);
            }

            setProcessBarMax(dlgDataConverts.Count);
            int count = 0;
            bool hasErrOccur = false;
            foreach (DlgDataConvert dlgDataConvert in dlgDataConverts)
            {
                setProcessBarCurrent(++count);

                dlgDataConvert.UseAppendGP = useGP;
                bool result = dlgDataConvert.Operate();
                if (!useGP)
                {
                    totalCount = totalCount + dlgDataConvert.TotalCount;
                    errorCount = errorCount + dlgDataConvert.ErrorCount;
                    rightCount = rightCount + dlgDataConvert.RightCount;
                }
                else
                {
                    if (!result) hasErrOccur = true;
                }

                if (stopAnyway) return false;
            }
            if (!useGP)
            {
                if (errorCount > 0)
                {
                    LogHelper.WriteLog("数据入库完毕。待入库总数：" + totalCount + "个；成功：" + rightCount + "个；失败：" + errorCount + "个。\n", zjgisLogType.zjgisLogError);
                }
                else
                {
                    LogHelper.WriteLog("数据入库完毕。待入库总数：" + totalCount + "个；成功：" + rightCount + "个；失败：" + errorCount + "个。\n", zjgisLogType.zjgisLogDone);
                }
            }
            return !hasErrOccur;
        }

        /// <summary>
        /// 验证建库方案中的代码是否完整
        /// </summary>
        /// <returns></returns>
        public bool Validate()
        {
            if (pFeatClsLstSource == null || pFeatClsLstSource.Count == 0)
            {
                LogHelper.WriteErrLog("请选择数据源。\n");
                return false;
            }

            if (fcodeRelationPt == null || fcodeRelationLn == null || fcodeRelationPy == null || fcodeRelationAnno == null)
            {
                LogHelper.WriteErrLog("请选择建库方案。\n");
                return false;
            }

            if (sourceCodeName == null || sourceCodeName == "")
            {
                LogHelper.WriteErrLog("请设置数据源入库的代码字段。\n");
                return false;
            }

            LogHelper.WriteLog("开始对建库方案的代码完整性进行检验，该操作所需时间可能较长，请耐心等候...");

            setProcessBarMax(pFeatClsLstSource.Count);

            int count = 0;

            foreach (IFeatureClass pFeatCls in pFeatClsLstSource)
            {
                setProcessBarCurrent(count++);

                LogHelper.WriteLog("正在检查数据源[" + pFeatCls.AliasName + "]中是否有建库方案中未配置的代码...");

                int index = pFeatCls.FindField(sourceCodeName);

                bool noSourceField = false;

                switch (pFeatCls.FeatureType)
                {
                    case esriFeatureType.esriFTSimple:
                        if (index == -1) noSourceField = true;
                        break;
                    //对于注记，只有当建库方案中设置了代码对应关系，才需要检查
                    case esriFeatureType.esriFTAnnotation:
                    case esriFeatureType.esriFTCoverageAnnotation:
                        if (fcodeRelationAnno == null || fcodeRelationAnno.Count == 0)
                        {
                            LogHelper.WriteLog("数据源[" + pFeatCls.AliasName + "]为注记要素类，且建库方案中未配置注记的代码对应关系，所以无需检查。\n");
                            continue;
                        }
                        else if (index == -1)
                        {
                            noSourceField = true;
                        }
                        break;
                    default:
                        LogHelper.WriteErrLog("目标数据[" + pFeatCls.AliasName + "]的要素类型系统不支持，请检查。验证失败！\n");
                        continue;
                }

                if (noSourceField)
                {
                    LogHelper.WriteErrLog("目标数据[" + pFeatCls.AliasName + "]找不到入库依据字段[" + sourceCodeName + "]。验证失败！\n");
                    continue;
                }



                IQueryFilter pQueryFilter = new QueryFilterClass();
                pQueryFilter.SubFields = sourceCodeName;

                int maxCount = pFeatCls.FeatureCount(pQueryFilter);

                ArrayList fcodes = FieldHelper.GetUniqueValuesByQueryDef(pFeatCls, sourceCodeName);

                Hashtable fcodeRelation;
                switch (pFeatCls.FeatureType)
                {
                    case esriFeatureType.esriFTAnnotation:
                    case esriFeatureType.esriFTCoverageAnnotation:
                        fcodeRelation = fcodeRelationAnno;
                        break;
                    case esriFeatureType.esriFTSimple:
                        switch (pFeatCls.ShapeType)
                        {
                            case esriGeometryType.esriGeometryPoint:
                                fcodeRelation = fcodeRelationPt;
                                break;
                            case esriGeometryType.esriGeometryPolyline:
                                fcodeRelation = fcodeRelationLn;
                                break;
                            case esriGeometryType.esriGeometryPolygon:
                                fcodeRelation = fcodeRelationPy;
                                break;
                            default:
                                LogHelper.WriteErrLog("系统暂不支持数据源[" + pFeatCls.AliasName + "]的几何类型。验证失败！\n");
                                continue;
                        }
                        break;
                    default:
                        LogHelper.WriteErrLog("系统暂不支持数据源[" + pFeatCls.AliasName + "]的要素类型。验证失败！\n");
                        continue;
                }

                bool notFound = false;
                if (fcodes.Count > 0)
                {
                    string fcode;
                    for (int i = 0; i < fcodes.Count; i++)
                    {
                        fcode = fcodes[i].ToString();
                        if (!fcodeRelation.ContainsKey(fcode))
                        {
                            LogHelper.WriteErrLog("数据源[" + pFeatCls.AliasName + "]中为[" + fcode + "]的代码，建库方案中未设置！");
                            notFound = true;
                        }
                    }
                }

                LogHelper.WriteLog("数据源[" + pFeatCls.AliasName + "]的代码验证完毕。" + (notFound ? "\n" : "未发现建库方案中没有涉及到的代码。\n"));

                if (stopAnyway) return false;
            }

            LogHelper.WriteDoneLog("建库方案检验完毕。\n");

            return true;
        }

        #region Default functions for delegates
        /// <summary>
        /// 默认在控制台中对无法进行准确计算进度条的操作进行提示
        /// </summary>
        /// <param name="wait"></param>
        private void Waiting(bool wait)
        {
            if (wait)
                Console.WriteLine("A long time operation started...");
            else
                Console.WriteLine("The operation is done.");
        }
        #endregion
    }
}
